#pragma once

#include "../math/collision.h"

#include <cstdint>
#include <vector>
#include <string>
#include <unordered_map>

#include "scene_object.h"

namespace ray_tracing
{
	class camera_t;
	class material_t;
	class light_t;

	typedef std::vector<light_t*> lights_type;
	typedef std::unordered_map<std::wstring, camera_t*> cameras_type;
	typedef std::vector<material_t*> materials_type;

	class scene_t final
		: private scene_object_t
	{
	public:
		scene_t();
		~scene_t();
	public:
		const scene_nodes_t& get_objects() const;
		const lights_type& get_lights() const;
		camera_t* get_rendering_camera() const;
		camera_t* get_camera(const std::wstring& name) const;
	public:
		camera_t* add_camera(const std::wstring& name, float in_angle, float in_N, const pnt3f& in_pos,
			const vec3f& in_up, const vec3f& in_look_at);
		light_t* add_light(const pnt3f& origin, const vec3f& in_color);
		scene_object_t* add_sphere(const pnt3f& origin, float R, material_t* in_material);
		scene_object_t* add_plane(const vec3f& normal, float D, material_t* in_material);
		material_t* add_material(const vec3f& in_ambient_color, const vec3f& in_diffuse_color, const vec3f& in_specular_color, 
			float in_specular_power, float in_refraction_index, float in_reflection_contribution, float in_refraction_contribution);
	public:
		collision::collision_info_t intersect_with(const ray3f& ray, hit_param param) override;
	private:
		void set_rendering_camera(camera_t* camera);
	private:
		scene_t& operator=(scene_t rhs);
		scene_t(scene_t& rhs);
	private:
		scene_nodes_t objects;
		materials_type materials;
		lights_type lights;
		cameras_type cameras;
		camera_t* rendering_camera;
	};
}